#pragma once

class CCashdrawer
{
public:
    CCashdrawer(int nType, int nPort, int nMBType = -1);
    virtual ~CCashdrawer() {}

    virtual BOOL Initialize();
    virtual int Open() = 0;
    virtual int GetStatus() = 0;
    

    virtual BOOL InitIOEx(WORD wInputAddress, WORD wOutAddress) = 0;

    // zhwang: it is better to create a new parent class named CDevice for all devices, printer, cashdrawer.......
    // include Initialize/GetType/GetLastError methods.
    int GetType() const { return m_nType; }
    int GetLastError() const { return m_nError; }

protected:
    struct ComInfo
    {
        HANDLE hCom;
        int nParity;
        OVERLAPPED oWrite;
        OVERLAPPED oRead;
    };
    ComInfo m_ComInfo;
    int m_nType;
    int m_nPort;
		int m_nMBType;
    int m_nError;
};

class CComCashdrawer : public CCashdrawer
{
public:
    CComCashdrawer(int nPort);
    virtual ~CComCashdrawer();
    
    virtual BOOL Initialize();
    virtual int Open();
    virtual int GetStatus();

    virtual BOOL InitIOEx(WORD wInputAddress, WORD wOutAddress) {return TRUE;}
};

class CPTCashdrawer: public CCashdrawer
{
public:
    CPTCashdrawer(int nPort);
    virtual ~CPTCashdrawer();

    virtual BOOL Initialize();
    virtual int Open();
    virtual int GetStatus();

    virtual BOOL InitIOEx(WORD wInputAddress, WORD wOutAddress) {return TRUE;}

private:
    enum EPTPortType
    {
        ECOM,
        ELPT,
        EUSB,
        EUnkown
    };
    EPTPortType m_ePort;
};


class CMBCashdrawer : public CCashdrawer
{
public:
	CMBCashdrawer(int nMBType);
	virtual ~CMBCashdrawer();

	virtual BOOL Initialize();
	virtual int Open();
	virtual int GetStatus();

    virtual BOOL InitIOEx(WORD wInputAddress, WORD wOutAddress) {return TRUE;}

private:
	BOOL D525_Initialize();
	int D525_Open();
	int D525_GetStatus();
	
	BOOL N2600_Initialize();
	int N2600_Open();
	int N2600_GetStatus();

private:
	unsigned int m_nStatus;
	HINSTANCE m_hFkLib;
};

class CMBCashdrawer_N2600 : public CCashdrawer
{
public:
	CMBCashdrawer_N2600();
	virtual ~CMBCashdrawer_N2600();

	virtual BOOL Initialize();
	virtual int Open();
	virtual int GetStatus();

    virtual BOOL InitIOEx(WORD wInputAddress, WORD wOutAddress) {return TRUE;}

private:
	int GetGPIOVal(int nPort);
	BOOL SetGPIOVal(int nPort, int nVal);

private:
	unsigned int m_nStatus;
	 HINSTANCE m_hFkLib;

	 typedef int (*GETINT2PROC)(int, int*);
	 GETINT2PROC GPIO_R_PROC;
	 typedef int (*SETINT2PROC)(int, int);
	 SETINT2PROC GPIO_W_PROC;
};

class CMBCashdrawer_N2600_JF : public CCashdrawer
{
public:
    CMBCashdrawer_N2600_JF(int nPIN);
    virtual ~CMBCashdrawer_N2600_JF();


    virtual BOOL Initialize();
    virtual int Open();
    virtual int GetStatus();

    virtual BOOL InitIOEx(WORD wInputAddress, WORD wOutAddress)
    {
        m_wOAddress = wInputAddress;
        m_wIAddress = wOutAddress;

        return TRUE;
    }

private:
    DWORD GetGPIOVal(WORD wIOAddr);
    BOOL SetGPIOVal(WORD wIOAddr, DWORD dwVal);

    CMBCashdrawer_N2600_JF();


private:
    unsigned int m_nStatus;
    HINSTANCE m_hIOLib; 
    typedef bool (_stdcall *INITIO)();
    INITIO    GPIO_INIT_PROC;
    typedef void (_stdcall *SHUTDOWNIO)();
    SHUTDOWNIO GPIO_SHOWDOWN_PROC;
    typedef bool (_stdcall *SETIOVAL)(WORD, DWORD, BYTE);
    SETIOVAL GPIO_SETVAL_PROC;
    typedef bool (_stdcall *GETIOVAL)(WORD, PDWORD, BYTE);
    GETIOVAL GPIO_GETVAL_PROC;

private:
    bool m_bInit;
    
    WORD m_wOAddress;
    WORD m_wIAddress;

    int m_nPIN;

};